#pragma once

#include "GameConfiguration.h"
#include "EntityManager.h"
#include "ResourceManager.h"
#include "SDLInitializer.h"

#include <stack>
#include <queue>

struct SDL_Renderer;

namespace ZeEngine
{
    //Forward Declarations
    class IGameState;
    class B2ContactListener;
    class SDLInitializer;
    class GUISystem;
    class Event;
    class IEventListener;

    class GameEngine
    {
    public:
        GameEngine();
        ~GameEngine();

        bool Start(std::unique_ptr<IGameState> pInitialState, const std::string& configFile = "");

        void PushState(std::unique_ptr<IGameState> pGameState);
        void PopState();

        u32 GetDeltaMS();
        float GetDeltaSeconds();
        void AddEvent(std::unique_ptr<Event> pEvent);

        u32 GetFPS() { return m_fps; }
        GUISystem& GetGUISystem() { return *m_pGUISystem; }
        const GameConfiguration& GetConfiguration() { return m_Config; }
        ResourceManager& GetResourceManager() { return m_resourceManager; }
        EntityManager& GetEntityManager() { return *m_entityManager; }

        //IEventListener
        void AddEventListener(IEventListener* pListener);
        void RemoveEventListener(IEventListener* pListener);
        void HandleEvents();

	private:
        bool FrameFunc();

        void PreRender(SDL_Renderer* pRenderer, SDL_Texture* pRenderTexture);
        bool RenderFunc(f32 interpolation);
        void PostRender(SDL_Renderer* pRenderer, SDL_Texture* pRenderTexture);

        void PopStates();
        bool PushStates();

        bool Init(std::unique_ptr<IGameState> pInitialState, const std::string& configFile);
        bool InitializeSDL();

        void Destroy();

        void HandleException(std::exception_ptr eptr);

	private:		
		GameConfiguration       m_Config;

        bool                    m_started;

        //States
        std::stack<std::shared_ptr<IGameState>> m_States;
        std::shared_ptr<IGameState>             m_pGameState;
        std::queue<std::shared_ptr<IGameState>> m_pNewStates;

        Uint32                          m_PopStates;  

        u64                             m_deltaMS;

        SDLInitializer                  m_SDLInitializer;
        std::unique_ptr<EntityManager>  m_entityManager;
        ResourceManager                 m_resourceManager;

        u32                             m_fpsCounter;
        u32                             m_fps;

        GUISystem*                      m_pGUISystem;

        std::vector<std::unique_ptr<Event>>  m_events;
        std::vector<IEventListener*> m_eventListeners;
	};
}

